//; ---------------------------------------------------------------------------
//; Object 42 - Newtron enemy (GHZ)
//; ---------------------------------------------------------------------------


#include "newtron.h"

#include "../../sprite.h"
#include "../../objectsystemNEWER.h"
#include "missile.h"

static object *obj;

//EXTERN DEFINITIONS HERE
#define player objects[0]
extern object *objects;


//; ---------------------------------------------------------------------------
//; Animation script - Newtron enemy
//; ---------------------------------------------------------------------------
byte A_Newt_Blank[3] = {  0xF, 0xA, afEnd };
byte A_Newt_Drop[8] =  { 0x13, 0, 1, 3, 4, 5, afBack, 1 };
byte A_Newt_Fly1[4] =  {    2, 6, 7, afEnd };
byte A_Newt_Fly2[4] =  {    2, 8, 9, afEnd };
byte A_Newt_Fires[9] = { 0x13, 0, 1, 1, 2, 1, 1, 0, afRoutine };

byte *Ani_Newt[5] = { A_Newt_Blank, A_Newt_Drop, A_Newt_Fly1, A_Newt_Fly2, A_Newt_Fires };

//; ---------------------------------------------------------------------------
//; Sprite mappings - Newtron enemy (GHZ)
//; ---------------------------------------------------------------------------
byte M_Newt_Trans[16] = {  3,
		   0xEC, 0xD, 0, 0, 0xEC,	//; partially visible
		   0xF4,   0, 0, 8,  0xC,
		   0xFC, 0xE, 0, 9, 0xF4
};
byte M_Newt_Norm[16] =  {  3,
		   0xEC,   6, 0, 0x15, 0xEC,    //; visible
		   0xEC,   9, 0, 0x1B, 0xFC,
		   0xFC, 0xA, 0, 0x21, 0xFC
};
byte M_Newt_Fires[16] = {  3,
		   0xEC,   6, 0, 0x2A, 0xEC,    //; open mouth, firing
		   0xEC,   9, 0, 0x1B, 0xFC,
		   0xFC, 0xA, 0, 0x21, 0xFC
};
byte M_Newt_Drop1[21] = {  4,
		   0xEC,   6, 0, 0x30, 0xEC,    //; dropping
		   0xEC,   9, 0, 0x1B, 0xFC,
		   0xFC,   9, 0, 0x36, 0xFC,
		    0xC,   0, 0, 0x3C,  0xC
};
byte M_Newt_Drop2[16] = {  3,
		   0xF4, 0xD, 0, 0x3D, 0xEC,
		   0xFC,   0, 0, 0x20,  0xC,
		      4,   8, 0, 0x45, 0xFC
};
byte M_Newt_Drop3[11] = {  2,
		   0xF8, 0xD, 0, 0x48, 0xEC,
		   0xF8,   1, 0, 0x50,  0xC
};
byte M_Newt_Fly1a[16] = {  3,
		   0xF8, 0xD, 0, 0x48, 0xEC,    //; flying
		   0xF8,   1, 0, 0x50,  0xC,
		   0xFE,   0, 0, 0x52, 0x14
};
byte M_Newt_Fly1b[16] = {  3,
		   0xF8, 0xD, 0, 0x48, 0xEC,
		   0xF8,   1, 0, 0x50,  0xC,
		   0xFE,   4, 0, 0x53, 0x14
};
byte M_Newt_Fly2a[16] = {  3,
		   0xF8, 0xD, 0, 0x48, 0xEC,
		   0xF8,   1, 0, 0x50,  0xC,
		   0xFE,   0,0xE0, 0x52, 0x14
};
byte M_Newt_Fly2b[16] = {  3,
		   0xF8, 0xD,    0, 0x48, 0xEC,
		   0xF8,   1,    0, 0x50,  0xC,
		   0xFE,   4, 0xE0, 0x53, 0x14
};
byte M_Newt_Blank[1] = {  0  };

byte *Map_Newt[] = { M_Newt_Trans, M_Newt_Norm,
		     M_Newt_Fires, M_Newt_Drop1,
		     M_Newt_Drop2, M_Newt_Drop3,
		     M_Newt_Fly1a, M_Newt_Fly1b,
		     M_Newt_Fly2a, M_Newt_Fly2b,
		     M_Newt_Blank
};
//==========

void (*Newt_Index[3])() = { Newt_Main, Newt_Action, Newt_Delete };

//OBJECT:					; XREF: Obj_Index
void Newtron(object *_obj)
{
    obj = _obj;

    //moveq	#0,d0
    //move.b	obRoutine(a0),d0
    byte routine = obj->Routine/2;

    //move.w	Ring_Index(pc,d0.w),d1
    //jmp	Ring_Index(pc,d1.w)
    (*Newt_Index[routine])();
}

//; ===========================================================================

//Newt_Main:	; Routine 0
void Newt_Main()
{
    //addq.b	#2,obRoutine(a0)
    obj->Routine = obj->Routine + 2;

    //move.l	#Map_Newt,obMap(a0)
    obj->Map = Map_Newt;

    //move.w	#$49B,obGfx(a0)
    obj->Gfx = 0x49B;

    //move.b	#4,obRender(a0)
    obj->Render = 4;

    //move.b	#4,obPriority(a0)
    obj->Priority = 4;

    //move.b	#$14,obActWid(a0)
    obj->ActionWidth = 0x14;

    //move.b	#$10,obHeight(a0)
    obj->Height = 16;

    //move.b	#8,obWidth(a0)
    obj->Width = 8;

    Newt_Action(); 
}

void (*n_index[5])() = { chkdistance, type00_n , matchfloor, speed, type01_n };

//Newt_Action:	; Routine 2
void Newt_Action()
{
    //moveq	#0,d0
    //move.b	ob2ndRout(a0),d0
    byte secondRoutine = obj->secondRoutine;

    //move.w	@index(pc,d0.w),d1
    //jsr	@index(pc,d1.w)
    (*n_index[secondRoutine/2])();

    //lea	(Ani_Newt).l,a1
    byte **aniScript = Ani_Newt;

    //bsr.w	AnimateSprite
    AnimateSprite(obj, aniScript);

    //bra.w	RememberState
    RememberState(obj);
}   //; ===========================================================================

//@chkdistance:				; XREF: @index
void chkdistance()
{
    //bset	#0,obStatus(a0)
    obj->Status = obj->Status | 1;

    //move.w	(v_player+obX).w,d0
    word playerX = player.X;

    //sub.w	obX(a0),d0
    signed short distPlayerObj = playerX - obj->X;

    //bcc.s	@sonicisright
    if (distPlayerObj > 0)
    {
        //neg.w	d0
        distPlayerObj = -distPlayerObj;

        //bclr	#0,obStatus(a0)
        obj->Status = obj->Status - (obj->Status & 1);

    }
 
    //@sonicisright:
    //cmpi.w	#$80,d0		; is Sonic within $80 pixels of	the newtron?
    //bcc.s	@outofrange	; if not, branch
    if (distPlayerObj < 0x80)
    {
        //addq.b	#2,ob2ndRout(a0) ; goto @type00 next
        obj->secondRoutine = obj->secondRoutine + 2;

        //move.b	#1,obAnim(a0)
        obj->Anim = 1;

        //tst.b	obSubtype(a0)	; check	object type
        //beq.s	@istype00	; if type is 00, branch
        if (obj->Subtype != 0) 
	{
            //move.w	#$249B,obGfx(a0)
            obj->Gfx = 0x249B;

	    //move.b	#8,ob2ndRout(a0) ; goto @type01 next
            obj->secondRoutine = 8;

	    //move.b	#4,obAnim(a0)	; use different	animation
            obj->Anim = 4;

	}   //@outofrange:
    }//@istype00:
    //rts
}	

//; ===========================================================================

//@type00:				; XREF: @index
void type00_n()
{
    //cmpi.b	#4,obFrame(a0)	; has "appearing" animation finished?
    //bcc.s	@fall		; is yes, branch
    if (obj->Frame >= 4)
    {
        //bset	#0,obStatus(a0)
        obj->Status = obj->Status | 1;

        //move.w	(v_player+obX).w,d0
        word playerX = player.X;

        //sub.w	obX(a0),d0
        signed short distPlayerObj = playerX - obj->X;

        //bcc.s	@sonicisright2
        if (distPlayerObj > 0)
        {
            //bclr	#0,obStatus(a0)
            obj->Status = obj->Status - (obj->Status & 1);
        }
	//@sonicisright2:
        //rts
    }
    else //; ===========================================================================
    { 
        //@fall:
	//cmpi.b	#1,obFrame(a0)
        //bne.s	@loc_DE42
        if (obj->Frame == 1)
	{	
	    //move.b	#$C,obColType(a0)
            obj->ColType = 0xC;
        }

	//@loc_DE42:
	//bsr.w	ObjectFall
        ObjectFall(obj);

	//bsr.w	ObjFloorDist
        signed short floorDist = ObjFloorDist(obj);

	//tst.w	d1		; has newtron hit the floor?
        //bpl.s	@keepfalling	; if not, branch
        if (floorDist < 0)
        {
	    //add.w	d1,obY(a0)
            obj->Y = obj->Y + floorDist;

	    //move.w	#0,obVelY(a0)	; stop newtron falling
            obj->VelocityY = 0;

	    //addq.b	#2,ob2ndRout(a0)
            obj->secondRoutine = obj->secondRoutine + 2;
		
            //move.b	#2,obAnim(a0)
            obj->Anim = 2;

	    //btst	#5,obGfx(a0)
            //beq.s	@pppppppp
            if ((obj->Gfx & 32)==32)
            {
		//addq.b	#1,obAnim(a0)
                obj->Anim = obj->Anim + 1;
            }
   
	    //@pppppppp:
	    //move.b	#$D,obColType(a0)
            obj->ColType = 0xD;

	    //move.w	#$200,obVelX(a0) ; move newtron horizontally
            obj->VelocityX = 0x200;

	    //btst	#0,obStatus(a0)
            //bne.s	@keepfalling
            if ((obj->Status & 1) == 0)
            {
	        //neg.w	obVelX(a0)
                obj->VelocityX = -obj->VelocityX;
            }
	
            //@keepfalling:
	    //rts	
        }   //; ===========================================================================
    }
}

//@matchfloor:				; XREF: @index
void matchfloor()
{
    //bsr.w	SpeedToPos
    SpeedToPos(obj);

    //bsr.w	ObjFloorDist
    signed short floorDist = ObjFloorDist(obj);

    //cmpi.w	#-8,d1
    //blt.s	@nextroutine    
    //cmpi.w	#$C,d1
    //bge.s	@nextroutine
    if ((floorDist >= -8) && (floorDist < 0xC))
    {		
        //add.w	d1,obY(a0)	; match	newtron's position with floor
        obj->Y = obj->Y + floorDist;
    }
    else
    {
        //@nextroutine:
	//addq.b	#2,ob2ndRout(a0) ; goto @speed next
        obj->secondRoutine = obj->secondRoutine + 2;
    }
    //rts	
    
}	

//@speed:					; XREF: @index
void speed()
{
    //bsr.w	SpeedToPos
    SpeedToPos(obj);

    //rts
}   //; ===========================================================================

//@type01:				; XREF: @index
void type01_n()
{
    //cmpi.b	#1,obFrame(a0)
    //bne.s	@firemissile
    if (obj->Frame == 1)
    {
        //move.b	#$C,obColType(a0)
        obj->ColType = 0xC;
    }
   
    //@firemissile:
    //cmpi.b	#2,obFrame(a0) 
    //bne.s	@fail
    //tst.b	$32(a0)
    //bne.s	@fail
    
    if ((obj->Frame == 2) && (obj->Variables[0x32-0x28] == 0))
    {
        //move.b	#1,$32(a0)
        obj->Variables[0x32-0x28] = 1;

        //@fire:
        //bsr.w	FindFreeObj
        object *missile = FindFreeObj();

        //bne.s	@fail
        if (missile->ID == 0)
        {
            //move.b	#id_Missile,0(a1) ; load missile object
            missile->ID = id_Missile;
		
            //move.w	obX(a0),obX(a1)
            missile->X = obj->X;

            //move.w	obY(a0),obY(a1)
            missile->Y = obj->Y;

	    //subq.w	#8,obY(a1)
            missile->Y = missile->Y - 8;

	    //move.w	#$200,obVelX(a1) ; move missile to the right
            missile->VelocityX = 0x200;

	    //move.w	#$14,d0
            signed short moveDist = 0x18;

	    //btst	#0,obStatus(a0)	; is Newtron facing	left?
            //bne.s	@noflip	; if not, branch
            if ((obj->Status & 1) == 0)
            {
	        //neg.w	d0
                moveDist = -moveDist;

	        //neg.w	obVelX(a1)	; move missile to the left
                missile->VelocityX = -missile->VelocityX;
            }

	    //@noflip:
	    //add.w	d0,obX(a1)
            missile->X = missile->X + moveDist;

	    //move.b	obStatus(a0),obStatus(a1)
            missile->Status = obj->Status;
        
            //move.b	#1,obSubtype(a1)
            obj->Subtype = 1;
        }
        //@fail:
        //rts
    }
	
}

//; ===========================================================================

//Newt_Delete:	; Routine 4
void Newt_Delete()
{
    //bra.w	DeleteObject
    DeleteObject(obj);
}
